package com.cloudweb.oa.controller;

import cn.js.fan.db.ResultIterator;
import cn.js.fan.db.ResultRecord;
import cn.js.fan.util.DateUtil;
import cn.js.fan.util.NumberUtil;
import cn.js.fan.util.ParamUtil;
import cn.js.fan.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cloudweb.oa.cache.DepartmentCache;
import com.cloudweb.oa.cache.DeptUserCache;
import com.cloudweb.oa.cache.RoleCache;
import com.cloudweb.oa.cache.UserCache;
import com.cloudweb.oa.entity.Department;
import com.cloudweb.oa.entity.DeptUser;
import com.cloudweb.oa.entity.UserOfRole;
import com.cloudweb.oa.security.AuthUtil;
import com.cloudweb.oa.service.IUserOfRoleService;
import com.cloudweb.oa.utils.ConstUtil;
import com.cloudweb.oa.utils.SysUtil;
import com.cloudweb.oa.vo.Result;
import com.cloudwebsoft.framework.db.JdbcTemplate;
import com.cloudwebsoft.framework.util.LogUtil;
import com.redmoon.oa.android.Privilege;
import com.redmoon.oa.dept.DeptDb;
import com.redmoon.oa.dept.DeptMgr;
import com.redmoon.oa.dept.DeptUserDb;
import com.redmoon.oa.flow.*;
import com.redmoon.oa.flow.macroctl.MacroCtlMgr;
import com.redmoon.oa.flow.macroctl.MacroCtlUnit;
import com.redmoon.oa.flow.query.QueryScriptUtil;
import com.redmoon.oa.kernel.License;
import com.redmoon.oa.person.UserDb;
import com.redmoon.oa.person.UserMgr;
import com.redmoon.oa.pvg.RoleDb;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.sql.SQLException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Api(tags = "宏控件中用到的JS")
@Controller
public class MacroJsController {

    @Autowired
    HttpServletRequest request;

    @Autowired
    SysUtil sysUtil;

    @Autowired
    DeptUserCache deptUserCache;

    @Autowired
    RoleCache roleCache;

    @Autowired
    UserCache userCache;

    @Autowired
    IUserOfRoleService userOfRoleService;

    @Autowired
    DepartmentCache departmentCache;

    @Autowired
    AuthUtil authUtil;

    @ApiOperation(value = "富文本宏控件JS", notes = "富文本宏控件JS", httpMethod = "POST")
    @RequestMapping(value = "/flow/macro/macroJsUeditorCtl", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String macroJsUeditorCtl(Model model) {
        int flowId = ParamUtil.getInt(request, "flowId", -1);
        String fieldName = ParamUtil.get(request, "fieldName");
        String formCode = ParamUtil.get(request, "formCode");
        long id = ParamUtil.getLong(request, "id", -1); // id为智能模块中所编辑的记录的ID

        model.addAttribute("flowId", flowId);
        model.addAttribute("fieldName", fieldName);
        model.addAttribute("formCode", formCode);
        model.addAttribute("id", id);
        model.addAttribute("rootPath", sysUtil.getRootPath());

        return "th/flow/macro/macro_js_ueditor_ctl";
    }

    @ApiOperation(value = "文号宏控件JS", notes = "文号宏控件JS", httpMethod = "POST")
    @RequestMapping(value = "/flow/macro/macroJsPapernoCtl", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String macroJsPapernoCtl(Model model) {
        int flowId = ParamUtil.getInt(request, "flowId", -1);
        String desc = ParamUtil.get(request, "desc");
        String fieldName = ParamUtil.get(request, "fieldName");
        String[] ary = StrUtil.split(desc, ",");
        if (ary != null && ary.length == 2) {
            model.addAttribute("fieldNo", ary[0]);
            model.addAttribute("fieldYear", ary[1]);
        } else {
            model.addAttribute("msg", "参数不全");
            return "th/error/error";
        }

        String formName = ParamUtil.get(request, "cwsFormName");
        model.addAttribute("flowId", flowId);
        model.addAttribute("fieldName", fieldName);
        model.addAttribute("desc", desc);
        model.addAttribute("formName", formName);
        return "th/flow/macro/macro_js_paperno_ctl";
    }

    @ApiOperation(value = "取得文号", notes = "取得文号", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "flowId", value = "流程ID", required = true, dataType = "Integer"),
    })
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功")})
    @RequestMapping(value = "/flow/macro/getPaperno", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    @ResponseBody
    public Result<Object> getPaperno(@RequestParam(value="flowId") Integer flowId) {
        JSONObject json = new JSONObject();
        WorkflowDb wf = new WorkflowDb();
        wf = wf.getWorkflowDb(flowId);
        Leaf lf = new Leaf();
        lf = lf.getLeaf(wf.getTypeCode());
        FormDb fd = new FormDb();
        fd = fd.getFormDb(lf.getFormCode());
        FormDAO fdao = new FormDAO();
        fdao = fdao.getFormDAO(wf.getId(), fd);

        String fieldName = ParamUtil.get(request, "fieldName");
        FormField ff = fdao.getFormField(fieldName);
        String[] ary = ff.getDescription().split(",");

        PaperNoDb pnpn = new PaperNoDb();
        String noPrefix = ParamUtil.get(request, ary[0]);
        int year = ParamUtil.getInt(request, ary[1]);
        pnpn = pnpn.getPaperNoDb(noPrefix, year);
        if (pnpn != null) {
            // 组合
            int num = pnpn.getInt("cur_num") + 1;
            json.put("num", num);
        } else {
            json.put("num", 0);
        }

        /*String curVal = fdao.getFieldValue(fieldName);
        // 如果流程中已存有值，则不再生成新的值
        if (!StrUtil.isEmpty(curVal)) {
            // 如果已存在的值与文号当前值相等，则不再取新的文件，因为文号前缀及年份有可能会切换
            if (curVal.equals(String.valueOf(pnpn.getInt("cur_num")))) {
                json.put("num", curVal);
                return new Result<>(json);
            }
        }

        if (pnpn != null) {
            // 组合
            int num = pnpn.getInt("cur_num") + 1;

            // 存至表单中
            String prefix = ary[0];
            String nf = ary[1];
            fdao.setFieldValue(fieldName, num);
            fdao.setFieldValue(prefix, noPrefix);
            fdao.setFieldValue(nf, year);
            fdao.save();

            json.put("num", num);
        } else {
            json.put("num", 0);
        }*/
        return new Result<>(json);
    }

    @ApiOperation(value = "图标宏控件JS", notes = "图标宏控件JS", httpMethod = "POST")
    @RequestMapping(value = "/flow/macro/macroJsIconCtl", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String macroJsIconCtl(Model model) {
        String fieldName = ParamUtil.get(request, "fieldName");
        String formCode = ParamUtil.get(request, "formCode");

        model.addAttribute("fieldName", fieldName);
        model.addAttribute("formCode", formCode);

        FormField ff = null;
        // 如果是映射字段（来自于查询条件）
        if (fieldName.startsWith("other:")) {
            String[] ary = fieldName.split(":");
            if (ary.length == 5) {
                for (int i = 2; i < ary.length; i += 3) {
                    formCode = ary[i];
                    String showFieldName = ary[i + 2];

                    FormDb fd = new FormDb();
                    fd = fd.getFormDb(formCode);
                    if (!fd.isLoaded()) {
                        model.addAttribute("msg", "映射字段对应的表单: " + formCode + " 不存在");
                        return "th/error/error";
                    }
                    ff = fd.getFormField(showFieldName);
                }
            }
        } else {
            FormDb fd = new FormDb();
            fd = fd.getFormDb(formCode);
            if (!fd.isLoaded()) {
                model.addAttribute("msg", "表单: " + formCode + " 不存在");
                return "th/error/error";
            }
            ff = fd.getFormField(fieldName);
        }

        if (ff == null) {
            model.addAttribute("msg", "字段: " + fieldName + " 不存在");
            return "th/error/error";
        }

        String props = ff.getDescription();
        JSONObject jsonProps;
        jsonProps = JSONObject.parseObject(props);

        JSONArray jsonArr = jsonProps.getJSONArray("options");
        if (jsonArr == null) {
            model.addAttribute("msg", "控件描述中选项格式非法");
            return "th/error/error";
        }

        for (int i = 0; i < jsonArr.size(); i++) {
            JSONObject json = jsonArr.getJSONObject(i);
            String icon = json.getString("icon");
            String value = json.getString("value");

            String path;
            if (icon.startsWith("static/images/symbol/")) {
                path = "/" + icon;
            } else {
                path = "/static/images/symbol/" + icon;
            }
            json.put("path", path);
        }
        model.addAttribute("options", jsonArr);
        model.addAttribute("rootPath", sysUtil.getRootPath());

        return "th/flow/macro/macro_js_icon_ctl";
    }

    @ApiOperation(value = "嵌入查询JS", notes = "嵌入查询JS", httpMethod = "POST")
    @RequestMapping(value = "/flow/formQueryListEmbed", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String formQueryListEmbed(Model model) {
        String strcurpage = StrUtil.getNullString(request.getParameter("CPages"));
        if ("".equals(strcurpage)) {
            strcurpage = "1";
        }
        if (!StrUtil.isNumeric(strcurpage)) {
            model.addAttribute("msg", "标识非法");
            return "th/error/error";
        }

        FormQueryDb aqd = new FormQueryDb();
        int id = ParamUtil.getInt(request, "id", -1);

        if (id == -1) {
            model.addAttribute("msg", "id不能为空");
            return "th/error/error";
        }
        aqd = aqd.getFormQueryDb(id);

        String flowTypeCode = ParamUtil.get(request, "flowTypeCode");
        com.redmoon.oa.flow.Leaf lf = new com.redmoon.oa.flow.Leaf();
        lf = lf.getLeaf(flowTypeCode);

        String formCode = aqd.getTableCode();
        FormSQLBuilder fsb = new FormSQLBuilder();
        String sql = fsb.getSmartQueryOnFlowChangCondValue(request, aqd, lf);

        com.redmoon.oa.visual.FormDAO fdao = new com.redmoon.oa.visual.FormDAO();
        com.redmoon.oa.flow.FormDAO flowDao = new com.redmoon.oa.flow.FormDAO();

        String queryRelated = aqd.getQueryRelated();
        FormDb fdRelated = new FormDb();
        int queryRelatedId = -1;
        if (!"".equals(queryRelated)) {
            queryRelatedId = StrUtil.toInt(queryRelated, -1);
            FormQueryDb aqdRelated = aqd.getFormQueryDb(queryRelatedId);
            fdRelated = fdRelated.getFormDb(aqdRelated.getTableCode());
        }

        String colP = aqd.getColProps();
        org.json.JSONArray jsonArray;
        try {
            jsonArray = new org.json.JSONArray(colP);
            model.addAttribute("cols", jsonArray);
        } catch (JSONException e) {
            LogUtil.getLog(getClass()).error(e);
            model.addAttribute("msg", e.getMessage());
            return "th/error/error";
        }

        int total = 0;
        Iterator ir = null;
        try {
            // ListResult lr = fdao.listResult(formCode, sql, curpage, pagesize);
            // ir = lr.getResult().iterator();
            // 因为内嵌于页面中，所以不作分页处理，如果数据量太大，不适于放在页面中
            Vector vt = fdao.list(formCode, sql);
            total = vt.size();
            ir = vt.iterator();
        } catch (Exception e) {
            model.addAttribute("msg", e.getMessage());
            return "th/error/error";
        }

        WorkflowDb wf = new WorkflowDb();
        MacroCtlUnit mu = null;
        MacroCtlMgr mm = new MacroCtlMgr();
        DeptMgr dm = new DeptMgr();
        UserDb user = new UserDb();

        JSONArray ary = new JSONArray();
        while (ir.hasNext()) {
            fdao = (com.redmoon.oa.visual.FormDAO) ir.next();

            JSONObject jo = new JSONObject();

            for (FormField ff : fdao.getFields()) {
                if (ff.getType().equals(FormField.TYPE_MACRO)) {
                    mu = mm.getMacroCtlUnit(ff.getMacroType());
                    String macroCode = mu.getCode();
                    if ("macro_dept_select".equals(macroCode) || "macro_my_dept_select".equals(macroCode)) {
                        DeptDb dd = dm.getDeptDb(fdao.getFieldValue(ff.getName()));
                        jo.put(ff.getName(), dd.getName());
                    } else {
                        // jo.put(ff.getName(), fdao.getFieldValue(ff.getName()));
                        jo.put(ff.getName(), mu.getIFormMacroCtl().converToHtml(request, ff, fdao.getFieldValue(ff.getName())));
                    }
                } else {
                    jo.put(ff.getName(), fdao.getFieldValue(ff.getName()));
                }
            }
            // 写入id是用于flexigrid置于tr的id中，以便于生成checkbox
            jo.put("id", "" + fdao.getId());

            // 取得所关联的查询中的数据
            if (queryRelatedId != -1) {
                int flowId = StrUtil.toInt(fdao.getCwsId());
                flowDao = flowDao.getFormDAO(flowId, fdRelated);
                for (FormField ff : flowDao.getFields()) {
                    jo.put("rel." + ff.getName(), flowDao.getFieldValue(ff.getName()));
                }
            }

            long flowId = fdao.getFlowId();
            if (flowId == -1) {
                flowId = StrUtil.toLong(fdao.getCwsId(), -1);
            }
            String flowCreateDate = "";
            String flowTitle = "";
            String flowStarter = "";
            String flowStatus = "";
            if (flowId != -1 && flowId != 0) {
                wf = wf.getWorkflowDb((int) flowId);
                flowCreateDate = DateUtil.format(wf.getBeginDate(), "yyyy-MM-dd HH:mm");
                flowTitle = wf.getTitle();
                flowStarter = wf.getUserName();
                flowStarter = user.getUserDb(flowStarter).getRealName();
                flowStatus = wf.getStatusDesc();
            }

            jo.put("flowId", flowId);
            jo.put("flowBeginDate", flowCreateDate);
            jo.put("flowTitle", flowTitle);
            jo.put("flowStarter", flowStarter);
            jo.put("flowStatus", flowStatus);

            JSONObject jsonObject = new JSONObject();
            for (int i = 0; i < jsonArray.length(); i++) {
                try {
                    if ((Boolean) jsonArray.getJSONObject(i).get("hide")) {
                        continue;
                    }
                    String name = (String) jsonArray.getJSONObject(i).get("name");
                    if ("cws_op".equalsIgnoreCase(name)) {
                        continue;
                    }

                    if (jo.containsKey(name)) {
                        jsonObject.put("val", jo.get(name));
                    } else {
                        jsonObject.put("val", "");
                    }
                } catch (JSONException e) {
                    LogUtil.getLog(getClass()).error(e);
                }
            }

            ary.add(jsonObject);
        }

        if (total > 0) {
            String statDesc = aqd.getStatDesc();
            if ("".equals(statDesc)) {
                statDesc = "{}";
            }
            org.json.JSONObject json = null;
            try {
                json = new org.json.JSONObject(statDesc);

                JSONObject jo = new JSONObject();
                int n = 0;
                Iterator ir3 = json.keys();
                while (ir3.hasNext()) {
                    String key = (String) ir3.next();
                    String modeStat = json.getString(key);

                    double sumVal = FormSQLBuilder.getSUMOfSQL(sql, key);
                    if ("0".equals(modeStat)) {
                        jo.put(key, NumberUtil.round(sumVal, 2));
                    } else if ("1".equals(modeStat)) {
                        jo.put(key, "平均：" + NumberUtil.round(sumVal / total, 2));
                    }
                    n++;
                }
                if (n > 0) {
                    JSONObject jsonObject = new JSONObject();
                    for (int i = 0; i < jsonArray.length(); i++) {
                        if ((Boolean) jsonArray.getJSONObject(i).get("hide")) {
                            continue;
                        }
                        String name = (String) jsonArray.getJSONObject(i).get("name");
                        if ("cws_op".equalsIgnoreCase(name)) {
                            continue;
                        }

                        if (jo.containsKey(name)) {
                            jsonObject.put("val", jo.get(name));
                        } else {
                            String s = "";
                            if (i == 0) {
                                s = "合计";
                            }
                            jsonObject.put("val", s);
                        }
                    }
                    ary.add(jsonObject);
                }
            } catch (JSONException e) {
                LogUtil.getLog(getClass()).error(e);
            }
        }
        model.addAttribute("rows", ary);

        return "th/flow/macro/form_query_list_embed";
    }

    @ApiOperation(value = "嵌入查询列表JS", notes = "嵌入查询列表JS", httpMethod = "POST")
    @RequestMapping(value = "/flow/formQueryListScriptEmbed", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String formQueryListScriptEmbed(Model model) {
        if (!License.getInstance().isPlatform()) {
            model.addAttribute("msg", "系统版本中无此功能");
            return "th/error/error";
        }

        String strcurpage = StrUtil.getNullString(request.getParameter("CPages"));
        if ("".equals(strcurpage)) {
            strcurpage = "1";
        }
        if (!StrUtil.isNumeric(strcurpage)) {
            model.addAttribute("msg", "标识非法");
            return "th/error/error";
        }
        int pagesize = ParamUtil.getInt(request, "pageSize", 300);
        int curpage = Integer.parseInt(strcurpage);

        FormQueryDb aqd = new FormQueryDb();
        int id = ParamUtil.getInt(request, "id", -1);

        if (id == -1) {
            model.addAttribute("msg", "id不能为空");
            return "th/error/error";
        }

        String flowTypeCode = ParamUtil.get(request, "flowTypeCode");
        com.redmoon.oa.flow.Leaf lf = new com.redmoon.oa.flow.Leaf();
        lf = lf.getLeaf(flowTypeCode);

        aqd = aqd.getFormQueryDb(id);

        QueryScriptUtil qsu = new QueryScriptUtil();

        ResultIterator ri = qsu.executeQueryOnQueryInFlowChangCondValue(request, aqd, lf);
        /*if (ri == null) {
            model.addAttribute("msg", "查询结果为空");
            return "th/error/error";
        }*/

        String colP = aqd.getColProps();
        com.alibaba.fastjson.JSONArray jsonArray;
        try {
            jsonArray = com.alibaba.fastjson.JSONArray.parseArray(colP);
            model.addAttribute("cols", jsonArray);

            MacroCtlUnit mu = null;
            MacroCtlMgr mm = new MacroCtlMgr();
            DeptMgr dm = new DeptMgr();
            UserDb user = new UserDb();

            Vector<FormField> fields = new Vector<>();
            String formCode = qsu.getFormCode();
            if (formCode != null) {
                FormDb fd = new FormDb();
                fd = fd.getFormDb(formCode);
                if (fd.isLoaded()) {
                    fields = fd.getFields();
                }
            }

            JSONArray ary = new JSONArray();
            if (ri != null) {
                while (ri.hasNext()) {
                    ResultRecord rr = ri.next();
                    JSONObject jo = new JSONObject();
                    Map mapIndex = qsu.getMapIndex();
                    Iterator irMap = mapIndex.keySet().iterator();
                    int k = 0;
                    while (irMap.hasNext()) {
                        String keyName = (String) irMap.next();
                        jo.put(keyName, StrUtil.getNullStr(rr.getString(keyName)));
                    }

                    JSONObject jsonObject = new JSONObject();
                    for (int i = 0; i < jsonArray.size(); i++) {
                        String name = (String) jsonArray.getJSONObject(i).get("name");
                        if ((Boolean) jsonArray.getJSONObject(i).get("hide")) {
                            continue;
                        }
                        if ("cws_op".equalsIgnoreCase(name)) {
                            continue;
                        }
                        if (!jo.containsKey(name.toUpperCase())) {
                            continue;
                        }

                        String val = jo.get(name.toUpperCase()).toString();

                        for (FormField ff : fields) {
                            if (ff.getName().equalsIgnoreCase(name) && ff.getType().equals(FormField.TYPE_MACRO)) {
                                val = mm.getMacroCtlUnit(ff.getMacroType()).getIFormMacroCtl().converToHtml(request, ff, val);
                                break;
                            }
                        }
                        jsonObject.put(name, val);
                    }
                    ary.add(jsonObject);
                }

                if (ri.size() > 0) {
                    String statDesc = aqd.getStatDesc();
                    if ("".equals(statDesc)) {
                        statDesc = "{}";
                    }
                    org.json.JSONObject json = new org.json.JSONObject(statDesc);
                    JSONObject jo = new JSONObject();
                    Map mapFieldType = ri.getMapType();

                    Iterator ir3 = json.keys();
                    int n = 0;
                    while (ir3.hasNext()) {
                        String key = (String) ir3.next();
                        String modeStat = json.getString(key);

                        Integer iType = (Integer) mapFieldType.get(key.toUpperCase());
                        int fieldType = QueryScriptUtil.getFieldTypeOfDBType(iType);

                        double sumVal = FormSQLBuilder.getSUMOfSQL(qsu.getSql(), key);
                        if ("0".equals(modeStat)) {
                            if (fieldType == FormField.FIELD_TYPE_INT || fieldType == FormField.FIELD_TYPE_LONG) {
                                jo.put(key, (long) sumVal);
                            } else {
                                jo.put(key, NumberUtil.round(sumVal, 2));
                            }
                        } else if ("1".equals(modeStat)) {
                            jo.put(key, "平均：" + NumberUtil.round(sumVal / ri.size(), 2));
                        }
                        n++;
                    }
                    if (n > 0) {
                        JSONObject jsonObject = new JSONObject();
                        for (int i = 0; i < jsonArray.size(); i++) {
                            if ((Boolean) jsonArray.getJSONObject(i).get("hide")) {
                                continue;
                            }
                            String name = (String) jsonArray.getJSONObject(i).get("name");
                            if ("cws_op".equalsIgnoreCase(name)) {
                                continue;
                            }

                            if (jo.containsKey(name)) {
                                jsonObject.put(name, jo.get(name));
                            }
                        }
                        ary.add(jsonObject);
                    }
                }
            }

            model.addAttribute("rows", ary);
        } catch (JSONException e) {
            LogUtil.getLog(getClass()).error(e);
            model.addAttribute("msg", e.getMessage());
            return "th/error/error";
        }

        return "th/flow/form_query_list_script_embed";
    }

    @ApiOperation(value = "函数宏控件JS", notes = "函数宏控件JS", httpMethod = "POST")
    @RequestMapping(value = "/m/flow/macro/macro_formula_ctl", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String macroFormulaCtlMobile(Model model) {
        int flowId = ParamUtil.getInt(request, "flowId", -1);
        long id = ParamUtil.getLong(request, "id", -1);
        String fieldName = ParamUtil.get(request, "fieldName");
        String formCode = ParamUtil.get(request, "formCode");
        boolean editable = ParamUtil.getBoolean(request, "editable", false);

        FormDb fd = new FormDb();
        fd = fd.getFormDb(formCode);

        FormField ff = fd.getFormField(fieldName);

        String pageType = ParamUtil.get(request, "pageType");

        String desc = ff.getDescription();
        String params = null;
        String code = "";
        com.alibaba.fastjson.JSONObject json = com.alibaba.fastjson.JSONObject.parseObject(desc);
        code = json.getString("code");
        params = json.getString("params");

        String[] paramAry = StrUtil.split(params, ",");
        if (paramAry == null) {
            model.addAttribute("msg", "函数宏控件: " + ff.getTitle() + " 参数为空");
            return "th/error/error";
        }

        List<String> list = new ArrayList<>();
        StringBuffer sbParams = new StringBuffer();
        for (String fieldTitle : paramAry) {
            fieldTitle = fieldTitle.trim();
            FormField field = fd.getFormField(fieldTitle);
            if (field == null) {
                field = fd.getFormFieldByTitle(fieldTitle);
            }
            if (field == null) {
                if ("flowId".equalsIgnoreCase(fieldTitle)) {
                    StrUtil.concat(sbParams, "+','+", String.valueOf(flowId)); // @task 模块添加页面中没有元素id
                } else if ("id".equalsIgnoreCase(fieldTitle)) {
                    if (flowId != -1) {
                        com.redmoon.oa.flow.FormDAO fdao = new com.redmoon.oa.flow.FormDAO();
                        fdao = fdao.getFormDAO(flowId, fd);
                        StrUtil.concat(sbParams, "+','+", String.valueOf(fdao.getId())); // @task 模块添加页面中没有元素id
                    } else {
                        StrUtil.concat(sbParams, "+','+", String.valueOf(id)); // @task 模块添加页面中没有元素id
                    }
                } else if ("cws_status".equalsIgnoreCase(fieldTitle)) {
                    StrUtil.concat(sbParams, "+','+", "$(o('" + fieldTitle + "')).val()"); // @task 模块编辑页面中没有元素cws_status
                } else if ("cws_id".equalsIgnoreCase(fieldTitle)) {
                    StrUtil.concat(sbParams, "+','+", "$(o('" + fieldTitle + "')).val()"); // @task 模块编辑页面中没有元素cws_status
                } else if ("formCode".equalsIgnoreCase(fieldTitle)) {
                    StrUtil.concat(sbParams, "+','+", formCode);
                } else if ("cws_quote_id".equalsIgnoreCase(fieldTitle)) {
                    long cwsQuoteId = -1;
                    if (ConstUtil.PAGE_TYPE_FLOW.equals(pageType) || ConstUtil.PAGE_TYPE_FLOW_SHOW.equals(pageType)) {
                        com.redmoon.oa.flow.FormDAO fdao = new com.redmoon.oa.flow.FormDAO();
                        fdao = fdao.getFormDAO(flowId, fd);
                        cwsQuoteId = fdao.getCwsQuoteId();
                    } else if (id != -1) {
                        com.redmoon.oa.visual.FormDAO fdao = new com.redmoon.oa.visual.FormDAO();
                        fdao = fdao.getFormDAO(id, fd);
                        cwsQuoteId = fdao.getCwsQuoteId();
                    }
                    StrUtil.concat(sbParams, "+','+", "(" + String.valueOf(cwsQuoteId) + ")");
                } else {
                    // $开头表示父表单
                    if (fieldTitle.startsWith("$")) {
                        StrUtil.concat(sbParams, "+','+", "jQuery(window.parent.o('" + fieldTitle.substring(1) + "')).val()");
                    } else {
                        StrUtil.concat(sbParams, "+','+", "'" + fieldTitle + "'");
                    }
                }
            } else {
                list.add(field.getName());
                StrUtil.concat(sbParams, "+','+", "o('" + fieldTitle + "').value");
            }
        }

        Privilege pvg = new Privilege();
        String skey = pvg.getSkey(authUtil.getUserName());
        model.addAttribute("skey", skey);

        model.addAttribute("fieldList", list);
        model.addAttribute("args", params);
        model.addAttribute("params", sbParams.toString());
        model.addAttribute("editable", editable);
        model.addAttribute("fieldName", fieldName);
        model.addAttribute("code", code);

        return "th/m/flow/macro/macro_formula_ctl";
    }

    @ApiOperation(value = "省份宏控件JS（手机端）", notes = "省份宏控件JS（手机端）", httpMethod = "POST")
    @RequestMapping(value = "/m/flow/macro/macro_province_select", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String macroProvinceSelectMobile(Model model) {
        String formCode = ParamUtil.get(request, "formCode");
        String fieldName = ParamUtil.get(request, "fieldName");
        FormDb fd = new FormDb();
        fd = fd.getFormDb(formCode);
        FormField ff = fd.getFormField(fieldName);

        String relateStr = ff.getDefaultValueRaw();
        if ("".equals(relateStr)) {
            relateStr = ff.getDescription();
        }
        String[] ary = StrUtil.split(relateStr, ",");
        boolean isCity = false, isCountry = false;

        String cityId = "", countryId = "";
        if (ary != null) {
            if (ary.length >= 1) {
                isCity = true;
                cityId = ary[0];
            }
            if (ary.length == 2) {
                isCountry = true;
                countryId = ary[1];
            }
        }

        model.addAttribute("isCity", isCity);
        model.addAttribute("isCountry", isCountry);
        model.addAttribute("cityId", cityId);
        model.addAttribute("countryId", countryId);
        model.addAttribute("fieldName", fieldName);

        return "th/m/flow/macro/macro_province_select";
    }

    @ApiOperation(value = "嵌套表格2宏控件JS", notes = "嵌套表格2宏控件JS", httpMethod = "POST")
    @RequestMapping(value = "/m/flow/macro/nest_sheet", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String macroNestSheet(Model model) {
        String parentFormCode = ParamUtil.get(request, "formCode");
        String fieldName = ParamUtil.get(request, "fieldName");
        FormDb fd = new FormDb();
        fd = fd.getFormDb(parentFormCode);
        FormField nestField = fd.getFormField(fieldName);
        int flowId = ParamUtil.getInt(request, "flowId", com.redmoon.oa.visual.FormDAO.NONEFLOWID);
        String pageType = ParamUtil.get(request, "pageType");

        boolean isAutoSel = false;
        String nestFormCode = "", filter = "";
        try {
            String defaultVal = StrUtil.decodeJSON(nestField.getDescription());
            org.json.JSONObject json = new org.json.JSONObject(defaultVal);
            try {
                if (json.has("isAutoSel")) {
                    isAutoSel = json.getInt("isAutoSel") == 1;
                }
                nestFormCode = json.getString("destForm");
                if (json.has("filter")) {
                    filter = json.getString("filter");
                }
            } catch (Exception e) {
                LogUtil.getLog(getClass()).error(e);
            }
        } catch (JSONException e) {
            LogUtil.getLog(getClass()).error(e);
        }

        if (isAutoSel) {
            // 为了获取主表单中的值,解析配置条件中的主表所配置的字段并获取签到表的表单编码用于刷新表格
            String mainFormFieldNames = "";
            Pattern p = Pattern.compile("\\{\\$([A-Z0-9a-z-_@\\u4e00-\\u9fa5\\xa1-\\xff]+)\\}", // 前为utf8中文范围，后为gb2312中文范围
                    Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
            Matcher m = p.matcher(filter);
            while (m.find()) {
                String fName = m.group(1);
                if ("cwsCurUser".equals(fName) || "curUser".equals(fName) || "curUserDept".equals(fName) || "curUserRole".equals(fName) || fName.equals("admin.dept")) {
                    continue;
                }
                // 当条件为包含时，fieldName以@开头
                if (fName.startsWith("@")) {
                    fName = fName.substring(1);
                }
                if (mainFormFieldNames.length() == 0) {
                    mainFormFieldNames = fName;
                } else {
                    mainFormFieldNames += "," + fName;
                }
            }
            String mainId = ParamUtil.get(request, "mainId");

            model.addAttribute("mainFormFieldNames", mainFormFieldNames);
        }
        model.addAttribute("flowId", flowId);
        model.addAttribute("isAutoSel", isAutoSel);
        model.addAttribute("pageType", pageType);
        model.addAttribute("parentFormCode", parentFormCode);
        model.addAttribute("nestFormCode", nestFormCode);
        model.addAttribute("nestFieldName", fieldName);
        return "th/m/flow/macro/nest_sheet";
    }

    @ApiOperation(value = "省份宏控件JS", notes = "省份宏控件JS", httpMethod = "POST")
    @RequestMapping(value = "/flow/macro/macroJsProvinceSelectCtl", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String macroJsProvinceSelectCtl(Model model) {
        String fieldName = ParamUtil.get(request, "fieldName");
        String formCode = ParamUtil.get(request, "formCode");
        String rid = ParamUtil.get(request, "rid");
        boolean isCity = ParamUtil.getBoolean(request, "isCity", true);
        boolean isCountry = ParamUtil.getBoolean(request, "isCountry", true);
        String cityId = ParamUtil.get(request, "cityId");
        String countryId = ParamUtil.get(request, "countryId");

        model.addAttribute("fieldName", fieldName);
        model.addAttribute("formCode", formCode);
        model.addAttribute("rid", rid);
        model.addAttribute("isCity", isCity);
        model.addAttribute("isCountry", isCountry);
        model.addAttribute("cityId", cityId);
        model.addAttribute("countryId", countryId);
        return "th/flow/macro/macro_js_province_select";
    }

    @ApiOperation(value = "文号宏控件JS（手机端）", notes = "文号宏控件JS（手机端）", httpMethod = "POST")
    @RequestMapping(value = "/m/flow/macro/macro_paperno_ctl", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String macroPapernoCtlMobile(Model model) {
        int flowId = ParamUtil.getInt(request, "flowId", -1);
        String fieldName = ParamUtil.get(request, "fieldName");

        String formCode = ParamUtil.get(request, "formCode");
        FormDb fd = new FormDb();
        fd = fd.getFormDb(formCode);
        FormField ff = fd.getFormField(fieldName);
        String desc = ff.getDescription();

        String[] ary = StrUtil.split(desc, ",");
        if (ary != null && ary.length == 2) {
            model.addAttribute("fieldNo", ary[0]);
            model.addAttribute("fieldYear", ary[1]);
        } else {
            model.addAttribute("msg", "参数不全");
            return "th/error/error";
        }

        String formName = ParamUtil.get(request, "cwsFormName");
        model.addAttribute("flowId", flowId);
        model.addAttribute("fieldName", fieldName);
        model.addAttribute("desc", desc);
        model.addAttribute("formName", formName);
        return "th/m/flow/macro/macro_paperno_ctl";
    }

    @ApiOperation(value = "角色中用户宏控件JS", notes = "角色中用户宏控件JS", httpMethod = "POST")
    @RequestMapping(value = "/flow/macro/macroJsRoleUserSelectCtl", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String macroJsRoleUserSelectCtl(Model model) {
        // 联动字段user字段列出对应角色中的用户
        String userField = ParamUtil.get(request, "userField");
        String field = ParamUtil.get(request, "field");
        String formCode = ParamUtil.get(request, "formCode");
        String formName = ParamUtil.get(request, "cwsFormName");
        String roles = ParamUtil.get(request, "roles");

        model.addAttribute("formName", formName);
        model.addAttribute("formCode", formCode);
        model.addAttribute("userField", userField);
        model.addAttribute("field", field);
        model.addAttribute("roles", roles);
        return "th/flow/macro/macro_js_role_user_select";
    }

    @ApiOperation(value = "取得与用户同部门中对应角色的用户", notes = "取得与用户同部门中对应角色的用户", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "roleCodes", value = "角色编码，以逗号分隔", required = true, dataType = "String"),
            @ApiImplicitParam(name = "userName", value = "用户名", required = true, dataType = "String"),
    })
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功")})
    @RequestMapping(value = "/flow/macro/getRoleUserRelatedToUser", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    @ResponseBody
    public Result<Object> getRoleUserRelatedToUser(@RequestParam(value = "roleCodes") String roleCodes, @RequestParam(value = "userName") String userName) {
        String[] arrRoles = roleCodes.split(",");

        JSONObject json = new JSONObject();
        Map<String, String> map = new HashMap<>();
        StringBuilder sbUserName = new StringBuilder();
        StringBuilder sbRealName = new StringBuilder();

        String[] ary = userName.split(",");
        for (String uName : ary) {
            List<DeptUser> list = deptUserCache.listByUserName(uName);
            for (DeptUser deptUser : list) {
                String deptCode = deptUser.getDeptCode();

                Department department = departmentCache.getDepartment(deptCode);
                if (department.getIsHide() == 1) {
                    continue;
                }

                boolean isFound = false;
                // 把同部门的，全部都取出来
                for (String roleCode : arrRoles) {
                    List<UserOfRole> listUserOfRole = userOfRoleService.listByRoleCode(roleCode);
                    for (UserOfRole userOfRole : listUserOfRole) {
                        List<DeptUser> listDu = deptUserCache.listByUserName(userOfRole.getUserName());
                        for (DeptUser du : listDu) {
                            if (deptCode.equals(du.getDeptCode())) {
                                if (!map.containsKey(du.getUserName())) {
                                    StrUtil.concat(sbUserName, ",", du.getUserName());
                                    StrUtil.concat(sbRealName, ",", userCache.getUser(du.getUserName()).getRealName());
                                    map.put(du.getUserName(), "");
                                }
                                isFound = true;
                            }
                        }
                    }
                }

                if (!isFound) {
                    // 往上级部门找，找到一个就退出查找
                    DeptDb dd = new DeptDb();
                    dd = dd.getDeptDb(deptCode);
                    UserMgr um = new UserMgr();
                    DeptUserDb du = new DeptUserDb();
                    DeptDb parentDept = dd.getDeptDb(dd.getParentCode());
                    while (parentDept != null && parentDept.isLoaded()) {
                        // 遍历父节点下的所有人员
                        for (DeptUserDb deptUserDb : du.list(parentDept.getCode())) {
                            // 取得用户的所有角色
                            UserDb ud = um.getUserDb(deptUserDb.getUserName());
                            RoleDb[] roles = ud.getRoles();
                            for (RoleDb role : roles) {
                                for (String roleCode : arrRoles) {
                                    if (roleCode.equals(role.getCode())) {
                                        if (!map.containsKey(deptUserDb.getUserName())) {
                                            StrUtil.concat(sbUserName, ",", deptUserDb.getUserName());
                                            StrUtil.concat(sbRealName, ",", userCache.getUser(deptUserDb.getUserName()).getRealName());
                                            map.put(deptUserDb.getUserName(), "");
                                        }
                                        isFound = true;
                                        break;
                                    }
                                }
                            }
                        }
                        if (isFound) {
                            break;
                        }

                        // 20161207 使支持根节点
                        if (parentDept.getCode().equals(DeptDb.ROOTCODE)) {
                            break;
                        } else {
                            // 取得再往上一个父节点
                            parentDept = parentDept.getDeptDb(parentDept.getParentCode());
                        }
                    }
                }

                if (isFound) {
                    break;
                }
            }
        }

        json.put("userName", sbUserName.toString());
        json.put("realName", sbRealName.toString());
        return new Result<>(json);
    }

    @ApiOperation(value = "用户多选框宏控件JS", notes = "用户多选框宏控件JS", httpMethod = "POST")
    @RequestMapping(value = "/flow/macro/macroJsUserMultiSelectWinCtl", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String macroJsUserMultiSelectWinCtl(Model model) {
        // 联动字段user字段列出对应角色中的用户
        String userField = ParamUtil.get(request, "userField");
        String field = ParamUtil.get(request, "field");
        String formCode = ParamUtil.get(request, "formCode");
        String formName = ParamUtil.get(request, "cwsFormName");
        String roles = ParamUtil.get(request, "roles");

        model.addAttribute("formName", formName);
        model.addAttribute("formCode", formCode);
        model.addAttribute("userField", userField);
        model.addAttribute("field", field);
        model.addAttribute("roles", roles);

        return "th/flow/macro/macro_js_user_multi_select_win";
    }

    @ApiOperation(value = "用户多选框宏控件JS（手机端）", notes = "用户多选框宏控件JS（手机端）", httpMethod = "POST")
    @RequestMapping(value = "/m/flow/macro/macro_user_multi_select_win", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String macroUserMultiSelectMobile(Model model) {
        String roles = "";
        String userField = "";
        String fieldName = ParamUtil.get(request, "fieldName");
        String formCode = ParamUtil.get(request, "formCode");
        FormDb fd = new FormDb();
        fd = fd.getFormDb(formCode);
        FormField ff = fd.getFormField(fieldName);
        String desc = ff.getDescription();
        if (StringUtils.isNotEmpty(desc)) {
            org.json.JSONObject json;
            try {
                json = new org.json.JSONObject(desc);
                if (json.has("roles")) {
                    roles = json.getString("roles");
                }
                if (json.has("userField")) {
                    userField = json.getString("userField");
                }
            } catch (JSONException e) {
                LogUtil.getLog(getClass()).error(e);
            }
        }

        model.addAttribute("field", fieldName);
        model.addAttribute("userField", userField);
        model.addAttribute("roles", roles);

        return "th/m/flow/macro/macro_user_multi_select_win";
    }

    @ApiOperation(value = "角色中用户宏控件JS（手机端）", notes = "角色中用户宏控件JS（手机端）", httpMethod = "POST")
    @RequestMapping(value = "/m/flow/macro/role_user_select", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String macroRoleUserSelect(Model model) {
        // 联动字段user字段列出对应角色中的用户
        String roles = "";
        String userField = "";
        String fieldName = ParamUtil.get(request, "fieldName");
        String formCode = ParamUtil.get(request, "formCode");
        FormDb fd = new FormDb();
        fd = fd.getFormDb(formCode);
        FormField ff = fd.getFormField(fieldName);
        String desc = ff.getDescription();
        if (StringUtils.isNotEmpty(desc)) {
            if (desc.startsWith("{")) {
                org.json.JSONObject json;
                try {
                    json = new org.json.JSONObject(desc);
                    if (json.has("roles")) {
                        roles = json.getString("roles");
                    }
                    if (json.has("userField")) {
                        userField = json.getString("userField");
                    }
                } catch (JSONException e) {
                    LogUtil.getLog(getClass()).error(e);
                }
            } else {
                roles = desc;
            }
        }

        model.addAttribute("field", fieldName);
        model.addAttribute("userField", userField);
        model.addAttribute("roles", roles);

        return "th/m/flow/macro/role_user_select";
    }
}
